#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>

#include <sys/stat.h>
#include <fcntl.h>

    // 1.
    // 一个守护进程举例
    // printf("Daemon process started!\n");
    // for (;;)
    // {
    //     sleep(1);
    // }
    // printf("bye!\n");

    // 2.
    // 为了实现上面的目的,应该在守护进程中使用下面的代码:
    // 这里的fd可以理解为inode
    // int fd;
    // // 通过读写方式打开文件
    // fd = open("/dev/null",O_RDWR);
    // // 先关闭STDIN_FILENO(这是规矩,已经打开的描述符,改动前先关闭),类似于指针指向null,让/dev/null成为标准输出
    // dup2(fd, STDIN_FILENO);
    // // 先关闭STDOUT_FILENO,类似于指针指向null,让/dev/null成为标准输出
    // dup2(fd, STDOUT_FILENO);

    // if (fd > STDERR_FILENO)
    // {
    //     close(fd);  // 释放资源
    // }

int ngx_daemon(){
    int fd;
    switch (fork())
    {
    case -1:
        // 这里fork出现错误,可以写日志相关的
        return -1;
    case 0:
        // 子进程,让他执行下面的代码,直接break;
        break;

    // 父进程,直接退出
    default:
        exit(0);
    }

    // 到了这里应该只有子进程了
    if (setsid() == -1)
    {
        // 记录日志
        return -1;
    }

    umask(0);   // 不要限制文件权限
    fd = open("/dev/null", O_RDWR);
    if (fd == -1)
    {
        // 记录日志
        return -1;
    }

    if (dup2(fd, STDIN_FILENO) == -1)
    {
        // 记录日志
        return -1;
    }

    if (dup2(fd, STDOUT_FILENO)== -1)
    {
        // 记录日志
        return -1;
    }

    if (fd > STDERR_FILENO)
    {
        if (close(fd) == -1)
        {
            // 记录日志
            return -1;
        }

    }
    return 1;
}

int main(int argc, char const *argv[])
{
    if (ngx_daemon() != 1)
    {
        // 创建守护进程失败, 可以做失败处理
        return -1;
    }
    else
    {
        // 守护进程创建成功
        // 执行剩下的操作
        for (;;)
        {
            sleep(1);
            printf("sleep for 1s, process id is %d!\n", getpid());
            // 向/dev/null中输出东西是没有用的
        }
    }

    return 0;
}
